﻿#region Creditos

/* Autor: Edilberto Sánchez Forero	*/
/* Email: esanchezfo@gmail.com		*/
/* Licencia: LGPL, Software Libre	*/
/* País: Colombia, Bogotá			*/

#endregion

#region Librerias

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Security.Permissions;
using System.IO;
using System.Reflection;
using System.Collections;
using ESF.General;
using ESF.General.Entity;

#endregion


namespace ESF.Web.ServerControls
{
	[AspNetHostingPermission(SecurityAction.Demand,
        Level = AspNetHostingPermissionLevel.Minimal),
    AspNetHostingPermission(SecurityAction.InheritanceDemand, 
        Level = AspNetHostingPermissionLevel.Minimal)]
	[ToolboxData("<{0}:GenericTreeView runat=\"server\"></{0}:GenericTreeView>")]
	public class GenericTreeView : TreeView, INamingContainer
	{
		#region Constantes
		
		public const char VALUESEPARATORCHAR = '|';

		private const int DIFX = -1;

        #endregion
	
	
		#region Delegados
		
		public delegate string DoTransformTextByLevel (Dictionary<string, string> pValueList);
		
		public delegate object [] DoSelectNodeGetChildren (Dictionary<string, string> pValueList, bool pFromExpand, int pDepth);
		public event DoSelectNodeGetChildren SelectNodeGetChildren;
		
		public delegate bool DoFilterNodeByValues (Dictionary<string, string> pValueList, int pNodeDepth);
		public event DoFilterNodeByValues FilterNodeByValues;
		
		public delegate void DoMarkNode (Dictionary<string, string> pValueList);
		public event DoMarkNode MarkNode;

		public delegate int DoGetNodeDepth (Dictionary<string, string> pValueList);
		public event DoGetNodeDepth GetNodeDepth;

        public delegate void DoThereIsNoChildrenNodes(Dictionary<string, string> pValueList);
        public event DoThereIsNoChildrenNodes ThereIsNoChildrenNodes;

		#endregion
		
		
		#region Miembros
		
		private List<DoTransformTextByLevel> _TrasformNodeTextByLevel;
		private List<DoTransformTextByLevel> _TrasformNodeToolTipByLevel;
		
		private int _SelectedNodeCountByFixedLevel;
		
		#endregion
		
	
		#region Propiedades

		public bool IncludeHyperLinks
		{
			set
			{
				ViewState ["IncludeHyperLinks"] = value;
			}
			get
			{
				if (ViewState ["IncludeHyperLinks"] == null) { return false; }

				return (bool) ViewState ["IncludeHyperLinks"];
			}
		}


		public string PublishFolderRelativePath
		{
			set
			{
				EnsureChildControls ();

				ViewState ["PublishFolderRelativePath"] = value;
			}
			get
			{
				return ViewState ["PublishFolderRelativePath"] as string;
			}
		}


		// Retorna un directorio absoluto
		public string PublishFolder
		{
			set
			{
				EnsureChildControls ();

				ViewState ["PublishFolder"] = value;
			}
			get
			{
				string pf;


				pf = ViewState ["PublishFolder"] as string;

				if (string.IsNullOrEmpty (pf))
				{
					return Path.GetDirectoryName (HttpContext.Current.Request.MapPath (HttpContext.Current.Request.AppRelativeCurrentExecutionFilePath));
				}
				else if (pf.StartsWith ("~"))
				{
					return HttpContext.Current.Request.MapPath (pf);
				}

				return pf;
			}
		}


		public string [] ExcludedExtensions
		{
			set
			{
				ViewState ["ExcludedExtensions"] = value;
			}
			get
			{
				string [] ext;
				
				
				ext = ViewState ["ExcludedExtensions"] as string [];

				if (ext == null) { return new string [] { ".aspx", ".cs", ".ascx", ".tmp" }; }

				return ext;
			}
		}


		public string ExtensionFilter
		{
			set
			{
				ViewState ["ExtensionFilter"] = value;
			}
			get
			{
				string ext;
				
				
				ext = ViewState ["ExtensionFilter"] as string;

				if (string.IsNullOrEmpty (ext)) { return "*.*"; }

				return ext;
			}
		}

		
		[Bindable(true)]
        [Category("Presentation")]
        [Description("Field that describes the level of node")]
        [Localizable(false)]
		public string LevelDescriptionDataMember
		{
			set { ViewState["LevelDescriptionDataMember"] = value; }
			get { return ViewState["LevelDescriptionDataMember"] as string; }
		}


		[Bindable(true)]
        [Category("Presentation")]
        [Description("Field that leads if there are children for the current node, must be boolean")]
        [Localizable(false)]
		public string AreThereChildrenDataMember
		{
			set { ViewState["AreThereChildrenDataMember"] = value; }
			get { return ViewState["AreThereChildrenDataMember"] as string; }
		}
		
		
		[Bindable(true)]
        [Category("Presentation")]
        [Description("Field for the text of node")]
        [Localizable(false)]
		public string TextDataMember
		{
			set { ViewState["TextDataMember"] = value; }
			get { return ViewState["TextDataMember"] as string; }
		}


		[Bindable(true)]
		[Category("Presentation")]
		[Description("Value Fields of node. They are added separated by comma and readed in the same way")]
		[Localizable(false)]
		public string ValueDataMembers
		{
			set { ViewState["ValueDataMembers"] = value; }
			get { return ViewState["ValueDataMembers"] as string; }
		}


		[Bindable(true)]
		[Category("Presentation")]
		[Description("CheckField of node")]
		[Localizable(false)]
		public string CheckDataMember
		{
			set { ViewState["CheckDataMember"] = value; }
			get { return ViewState["CheckDataMember"] as string; }
		}


		public string FirstValueDataMember
		{
			get 
			{
				string tmp;  


				tmp = ValueDataMembers;

				if (string.IsNullOrEmpty (tmp))
				{
					return null;
				}

				return tmp.Split (',') [0];
			}
		}
		
		
		[Bindable(true)]
		[Category("Presentation")]
		[Description("Tooltip field for node")]
		[Localizable(false)]
		public string ToolTipDataMember
		{
			set { ViewState["ToolTipDataMember"] = value; }
			get { return ViewState["ToolTipDataMember"] as string; }
		}


		[Bindable(true)]
		[Category("Presentation")]
		[Description("Image Icon URL field for node")]
		[Localizable(false)]
		public string ImageIconURLDataMember
		{
			set { ViewState["ImageIconURLDataMember"] = value; }
			get { return ViewState["ImageIconURLDataMember"] as string; }
		}


		[Bindable(true)]
		[Category("Presentation")]
		[Description("Navigate URL field for node")]
		[Localizable(false)]
		public string NavigateURLDataMember
		{
			set { ViewState["NavigateURLDataMember"] = value; }
			get { return ViewState["NavigateURLDataMember"] as string; }
		}
		
		
		[Bindable(true)]
		[Category("Presentation")]
		[Description("Max depth allowed to check from root node")]
		[Localizable(false)]
		public int SelectedMaxDepth
		{
			set { ViewState["SelectedMaxDepth"] = value; }
			get 
			{
				if (ViewState["SelectedMaxDepth"] == null)
				{
					return int.MaxValue;
				}
				
				return (int) ViewState["SelectedMaxDepth"]; 
			}
		}
		
		
		[Bindable(true)]
		[Category("Presentation")]
		[Description("If false all values of checked nodes are returned, else return values only for checked nodes with a defined fixed depth")]
		[Localizable(false)]
		[DefaultValue(false)]
		public bool ReturnValuesOnlyForLastDepth
		{
			set { ViewState["ReturnValuesOnlyForLastDepth"] = value; }
			get 
			{
				if (ViewState["ReturnValuesOnlyForLastDepth"] == null)
				{
					return false;
				}
				
				return (bool) ViewState["ReturnValuesOnlyForLastDepth"]; 
			}
		}
		
		
		[Bindable(true)]
		[Category("Presentation")]
		[Description("Set if the tree allow for any level mark more than one node")]
		[Localizable(false)]
		public bool AllowMultipleCheckForSameLevelNodes
		{
			set { ViewState["AllowMultipleCheckForSameLevelNodes"] = value; }
			get 
			{
				if (ViewState["AllowMultipleCheckForSameLevelNodes"] == null)
				{
					return true;
				}
				
				return (bool) ViewState["AllowMultipleCheckForSameLevelNodes"]; 
			}
		}
		
		
		public Type NodeDataType
		{
			set { ViewState ["NodeDataType"] = value; }
			get { return ViewState ["NodeDataType"] as Type; }
		}
		
		#endregion


        #region Constructor

        public GenericTreeView () : base ()
		{
			base.EnableClientScript = true;
			base.ShowLines = true;
			//base.ShowCheckBoxes = TreeNodeTypes.All;
			base.ExpandDepth = 0;
			//base.NodeWrap = true;
            //base.PopulateNodesFromClient = true;
			
            //TreeNodePopulate += TreeNode_PopulateNode;
            _TrasformNodeTextByLevel = new List<DoTransformTextByLevel> ();
			_TrasformNodeToolTipByLevel = new List<DoTransformTextByLevel> ();
			
			SelectedNodeChanged += GenericTreeView_SelectedNodeChanged;
            TreeNodeExpanded += GenericTreeView_TreeNodeExpanded;
			TreeNodeCheckChanged += TreeView_CheckedNode;

			NodeDataType = typeof (BasicReference);

			ValueDataMembers = "Code,Name,Extra_I,Extra_II,Extra_III,IsEnabled";
			TextDataMember = "Name";
			AreThereChildrenDataMember = "Extra_II";
			ImageIconURLDataMember = "Extra_III";
			NavigateURLDataMember = "Extra_I";
		}        

		#endregion
		
		
		#region Funciones del Arbol
		
		protected override void Render (HtmlTextWriter writer)
        {
            StringBuilder stbHTML;


			string resultHTML;
            
            
			stbHTML = new StringBuilder();

			using (StringWriter stringWriter = new StringWriter (stbHTML))
			{
				HtmlTextWriter tempWriter = new HtmlTextWriter (stringWriter);
				base.Render(tempWriter);
			}

			resultHTML = stbHTML.ToString ();

			resultHTML = resultHTML.Replace("<input type=\"checkbox\" ", "<input class=\"itemCheck\" type=\"checkbox\" onClick=\"" + Page.ClientScript.GetPostBackEventReference (this, null) + "\" ");
        
			resultHTML = resultHTML.Replace("white-space:nowrap;\"><a", "white-space:nowrap;\"><a class=\"itemLink" + (string.IsNullOrEmpty (ImageIconURLDataMember) ? string.Empty : " withIcon") + "\"");

			writer.Write (resultHTML);
		}
		
		#endregion
		
		
		#region Funciones de los Nodos
		
		public bool AddChildNode (string pParentNodeValue, object pData)
		{
			TreeNode parentNode;
			TreeNode parentParentNode;


			if (FindNodeByValue (pParentNodeValue, out parentParentNode, out parentNode))
			{
				AddNode (parentNode, pData);

				return true;
			}
			
			return false;
		}


		public bool DeleteNode (string pNodeValue)
		{
			TreeNode delNode;
			TreeNode parentDelNode;


			if (FindNodeByValue (pNodeValue, out parentDelNode, out delNode))
			{
				if (parentDelNode == null)
				{
					base.Nodes.Remove (delNode);

					return true;
				}
				else
				{
					parentDelNode.ChildNodes.Remove (delNode);

					return true;
				}
			}

			return false;
		}


		public void RemoveAllNodes ()
		{
			base.Nodes.Clear ();
		}

		
		public void SetRootNodes (object [] pDatas)
		{
			RemoveAllNodes ();
		
			
			if (pDatas == null)
			{
				Enabled = false;
				return;
			}


			Enabled = true;

			NodeDataType = pDatas [0].GetType();
			
			foreach (object value in pDatas)
			{
				AddRootNode (value);
			}
		}


		public void AddRootNode (object pData)
		{
			AddNode (null, pData);
		}
		
		
		public void AddNode (TreeNode pParentNode, object pData)
		{
			TreeNode node;
			TreeNode existentNode;
			TreeNode parentExistentNode;


			if (pData == null) { return; }


			node = GenerateNode (pData, (pParentNode == null ? DIFX : pParentNode.Depth));
			
			FindNode (pData, out parentExistentNode, out existentNode);
			

			if (existentNode != null)
			{
				existentNode.Text = node.Text;
				existentNode.Value = node.Value;
				existentNode.ShowCheckBox = node.ShowCheckBox;
			}
			else
			{
				if (pParentNode == null)
				{
					base.Nodes.Add (node);
				}
				else
				{
					pParentNode.ChildNodes.Add (node);
				}
			}
		}


		private bool FindNode (object pData, out TreeNode pParentResult, out TreeNode pResult)
		{
			object pDataValue;


			pDataValue = NodeDataType.GetProperty (FirstValueDataMember).GetValue (pData, null);

			if (pDataValue == null)
			{
				pParentResult = null;
				pResult = null;
				return false;
			}

			return FindNodeByValue (pDataValue.ToString (), out pParentResult, out pResult);
		}	


		private bool FindNodeByValue (string pDataValue, out TreeNode pParentResult, out TreeNode pResult)
		{
			return FindNodeRecursive (pDataValue, null, base.Nodes, out pParentResult, out pResult);
		}


		private bool FindNodeRecursive (string pDataValue, TreeNode pParent, TreeNodeCollection pChildNodes, out TreeNode pParentResult, out TreeNode pResult)
		{
			foreach (TreeNode n in pChildNodes)
			{
				if (GetNodeData (n) [FirstValueDataMember] == pDataValue)
				{
					pResult = n;
					pParentResult = pParent;
					return true;
				}
				else if (FindNodeRecursive (pDataValue, n, n.ChildNodes, out pParentResult, out pResult))
				{
					return true;
				}
			}

			pParentResult = null;
			pResult = null;
			return false;
		}
		
		
		private void AddNodes (TreeNode pParentNode, object [] pDatas)
		{
			if (pDatas != null)
			{
				foreach (object data in pDatas)
				{
					AddNode (pParentNode, data);
				}
			}
		}
		
		
		public TreeNode GenerateNode (object pData, int pNodeDepthParent)
		{
			object contenido;
			
			TreeNode nodo;

			bool? areThereChildren = null;

			PropertyInfo propiedad;
			
			string [] valueDataMembers;
			
			Dictionary <string,string> valoresNodo;


			if (pData == null) { return null; }

			
			if (NodeDataType == null)
			{
				throw new Exception ("No ha sido definido el tipo de dato del nodo que maneja el arbol");
			}
			
			nodo = new TreeNode ();
			
			#region Campo de Texto
			
			propiedad = NodeDataType.GetProperty (TextDataMember);
			
			if (propiedad == null)
			{
				throw new Exception (string.Format ("La propiedad {0} no esta definida en el tipo {1}", TextDataMember, NodeDataType.FullName));
			}
			
			contenido = propiedad.GetValue (pData, null);
			
			if (contenido != null)
			{
				nodo.Text = contenido.ToString ();
			}
			else
			{
				nodo.Text = string.Empty;
			}

			if (NodeDataType == typeof (BasicReference) && !(pData as BasicReference).IsEnabled.Value)
			{
				nodo.Text = "- " + nodo.Text + " -";
			}
			
			#endregion


			#region Campo de Hijos
			
			if (!string.IsNullOrEmpty (AreThereChildrenDataMember))
			{
				propiedad = NodeDataType.GetProperty (AreThereChildrenDataMember);
			
				if (propiedad == null)
				{
					throw new Exception (string.Format ("La propiedad {0} no esta definida en el tipo {1}", AreThereChildrenDataMember, NodeDataType.FullName));
				}
			
				contenido = propiedad.GetValue (pData, null);
			
				if (contenido == null)
				{
					areThereChildren = null;
				}
				else
				{
					areThereChildren = TextHelper.GetNullableBool (contenido.ToString ());
				}
			}

			#endregion


			#region Campo de Check
			
			if (!string.IsNullOrEmpty (CheckDataMember))
			{
				propiedad = NodeDataType.GetProperty (CheckDataMember);
			
				if (propiedad == null)
				{
					throw new Exception (string.Format ("La propiedad {0} no esta definida en el tipo {1}", CheckDataMember, NodeDataType.FullName));
				}
			
				contenido = propiedad.GetValue (pData, null);
			
				if (contenido != null)
				{
					nodo.Checked = TextHelper.GetBool (contenido.ToString (), false);
				}
			}
			
			#endregion
			

			#region Campo de Tooltip
			
			if (!string.IsNullOrEmpty (ToolTipDataMember))
			{
				propiedad = NodeDataType.GetProperty (ToolTipDataMember);
				
				if (propiedad == null)
				{
					throw new Exception (string.Format ("La propiedad {0} no esta definida en el tipo {1} para ser utilizada como tooltip", TextDataMember, NodeDataType.FullName));
				}
				
				contenido = propiedad.GetValue (pData, null);
				
				if (contenido != null)
				{
					nodo.ToolTip = contenido.ToString ();
				}
			}
			
			#endregion			
			

			valueDataMembers = ValueDataMembers.Replace (" ", string.Empty).Split (',');
			
			nodo.Value = string.Empty;
			
			
			#region Image URL
			
			if (!string.IsNullOrEmpty (ImageIconURLDataMember))
			{
				propiedad = NodeDataType.GetProperty (ImageIconURLDataMember);
				
				if (propiedad == null)
				{
					throw new Exception (string.Format ("La propiedad {0} no esta definida en el tipo {1} para ser utilizada como URL de imagen", ImageIconURLDataMember, NodeDataType.FullName));
				}
				
				contenido = propiedad.GetValue (pData, null);
				
				if (contenido != null)
				{
					nodo.ImageUrl = contenido.ToString ();
				}
			}
			
			#endregion


			#region Navigate URL

			if (!string.IsNullOrEmpty (NavigateURLDataMember))
			{
				propiedad = NodeDataType.GetProperty (NavigateURLDataMember);
				
				if (propiedad == null)
				{
					throw new Exception (string.Format ("La propiedad {0} no esta definida en el tipo {1} para ser utilizada como URL de navegación", NavigateURLDataMember, NodeDataType.FullName));
				}
				
				contenido = propiedad.GetValue (pData, null);
				
				if (contenido != null)
				{
					nodo.NavigateUrl = contenido.ToString ();
					nodo.Target = "_blank";
				}
			}

			#endregion


			#region ExtrDo Valores Nodo
			
			foreach (string campoValor in valueDataMembers)
			{
				propiedad = NodeDataType.GetProperty (campoValor);
				
				if (propiedad == null)
				{
					throw new Exception (string.Format ("La propiedad {0} no esta definida en el tipo {1}", campoValor, NodeDataType.FullName));
				}
				
				contenido = propiedad.GetValue (pData, null);
				
				if (contenido != null)
				{
					nodo.Value += contenido.ToString ();
				}
				
				nodo.Value += VALUESEPARATORCHAR;
			}

			nodo.Value = nodo.Value.Substring (0, nodo.Value.Length - 1);

			#endregion
			
			nodo.ShowCheckBox = (ShowCheckBoxes != TreeNodeTypes.None && pNodeDepthParent < SelectedMaxDepth);
			
			
			valoresNodo = GetNodeData (nodo);
			
			#region Presentacion Nodo

            // Esta la transformacion incluida en el listado para la profundidad actual
			if (_TrasformNodeTextByLevel.Count > 0
				&& pNodeDepthParent + 1 <= _TrasformNodeTextByLevel.Count
				&& _TrasformNodeTextByLevel [pNodeDepthParent + 1] != null)
			{
				nodo.Text = _TrasformNodeTextByLevel [pNodeDepthParent + 1] (valoresNodo);
			}
			
			// Esta la transformacion incluida en el listado para la profundidad actual
			if (_TrasformNodeToolTipByLevel.Count > 0
				&& pNodeDepthParent + 1 <= _TrasformNodeToolTipByLevel.Count
				&& _TrasformNodeToolTipByLevel [pNodeDepthParent + 1] != null)
			{
				nodo.ToolTip = _TrasformNodeToolTipByLevel [pNodeDepthParent + 1] (valoresNodo);
			}
			
			#endregion
			
			
			#region Filtrar Nodo

			if (pNodeDepthParent + 1 < SelectedMaxDepth)
			{			
				if (FilterNodeByValues != null)
				{
					if (FilterNodeByValues (valoresNodo, pNodeDepthParent + 1))
					{
						if (areThereChildren == null || areThereChildren.Value)
						{
							AddLoadingNode(ref nodo);
						}

						return nodo;
					}
					else
					{
						return null;
					}
				}

				if (areThereChildren == null || areThereChildren.Value)
				{
					AddLoadingNode(ref nodo);
				}
			}
			
			nodo.SelectAction = TreeNodeSelectAction.SelectExpand;

			return nodo;
			
			#endregion
		}


        private void AddLoadingNode(ref TreeNode pNodo)
        {
			pNodo.Expanded = null;
			pNodo.PopulateOnDemand = false;
			pNodo.ChildNodes.Add(new TreeNode("Cargando...", string.Empty));
            pNodo.SelectAction = TreeNodeSelectAction.SelectExpand;
        }
		
		
		public void DefineTextTransform (DoTransformTextByLevel pdelTransformarTextoXNivel, int pProfundidad)
		{
			for (int i = 0; i <= pProfundidad; i++)
			{
				if (_TrasformNodeTextByLevel.Count < i)
				{
					_TrasformNodeTextByLevel.Insert (i - 1, null);
				}
			}
			
			_TrasformNodeTextByLevel.Insert (pProfundidad, pdelTransformarTextoXNivel);
		}
		
		
		public void DefineToolTipTransform (DoTransformTextByLevel pdelTransformarTextoXNivel, int pProfundidad)
		{
			for (int i = 0; i <= pProfundidad; i++)
			{
				if (_TrasformNodeToolTipByLevel.Count < i)
				{
					_TrasformNodeToolTipByLevel.Insert (i - 1, null);
				}
			}
			
			_TrasformNodeToolTipByLevel.Insert (pProfundidad, pdelTransformarTextoXNivel);
		}
		
		
		public Dictionary<string, string> GetSelectedNodeData ()
		{
			return GetNodeData (base.SelectedNode);
		}
		
		
		public Dictionary<string, string> GetNodeData (TreeNode pNodo)
		{
			int intI;
			
			Dictionary<string, string> listaValores; 
			
			string [] nombresValor;
			string [] valores;
			
			
			
			if (pNodo == null) { return null; }
			
			listaValores = new Dictionary<string,string> ();
			
			nombresValor = ValueDataMembers.Replace (" ", string.Empty).Split (',');
			valores = pNodo.Value.Split (VALUESEPARATORCHAR);
			
			if (valores.Length != nombresValor.Length) 
			{
				for (intI = 0; intI < nombresValor.Length; intI ++)
				{
					listaValores.Add (nombresValor[intI], string.Empty);
				}
			}
			else
			{
				for (intI = 0; intI < nombresValor.Length; intI ++)
				{
					listaValores.Add (nombresValor[intI], valores[intI]);
				}
			}
			
			return listaValores;
		}
		
		
		private void CheckChildren (TreeNode pParentNode, bool ppCheck)
		{
			pParentNode.Checked = ppCheck;
		
			if (pParentNode.ChildNodes.Count == 0)
			{	
				return;
			}
		
			foreach (TreeNode childNode in pParentNode.ChildNodes)
			{
				CheckChildren (childNode, ppCheck);
			}
		}
		
		
		private void CheckParents (TreeNode pchildNode, bool ppCheck)
		{
			pchildNode.Checked = ppCheck;
		
			if (pchildNode.Parent != null)
			{	
				CheckParents (pchildNode.Parent, ppCheck);
			}
		}
		
		#endregion
		
		
		#region Funciones de Valores
		
		public List<Dictionary<string, string>> GetDatasForCheckedNodesOfLastDepth ()
		{
			return GetDatasForCheckedNodes (GetLastDepthOfCheckedNodes ());
		}
		
		
		public List<Dictionary<string, string>> GetDatasForCheckedNodes ()
		{
			return GetDatasForCheckedNodes (DIFX);
		}
		
		
		// Basado en 0
		public List<Dictionary<string, string>> GetDatasForCheckedNodes (int pDepthCheck)
		{
			List<Dictionary<string, string>> lDatas;
			
			
			lDatas = new List<Dictionary<string, string>> ();
			
			_SelectedNodeCountByFixedLevel = 0;
			
			foreach (TreeNode nodoPrincipal in base.Nodes)
			{
				GetDatasForCheckedNodes (nodoPrincipal, ref lDatas, pDepthCheck, GetLastDepthOfCheckedNodes ());
			}
			
			return lDatas;
		}
		
		
		private bool IsSelectedMaxDepth (TreeNode pNodo)
		{
			if (GetNodeDepth == null)
			{
				return (pNodo.Depth == SelectedMaxDepth);
			}
			
			return (SelectedMaxDepth == GetNodeDepth (GetNodeData (pNodo)));
		}
		
		
		private void GetDatasForCheckedNodes (TreeNode pParentNode, ref List<Dictionary<string, string>> plDatas, int pDepthCheck, int pUltimaDepthCheck)
		{
			string strMensaje;
		
		
			if (pParentNode.Checked)
			{
				if (IsSelectedMaxDepth (pParentNode))
				{
					_SelectedNodeCountByFixedLevel ++;
					
					if (!AllowMultipleCheckForSameLevelNodes && _SelectedNodeCountByFixedLevel > 1)
					{
						if (LevelDescriptionDataMember != null)
						{
							strMensaje = string.Format ("Ha marcado mas de un {0}, seleccione solo uno", GetNodeData (pParentNode) [LevelDescriptionDataMember]);
						}
						else
						{
							strMensaje = string.Format ("Ha marcado mas de un elemento de nivel {0}, seleccione solo uno", SelectedMaxDepth);							
						}
						
						throw new GenericInfoException (strMensaje);
					}
				
					plDatas.Add (GetNodeData (pParentNode));
				}
			
				else if (pDepthCheck != DIFX)
				{
					if (pParentNode.Depth == pDepthCheck)
					{
						plDatas.Add (GetNodeData (pParentNode));
					}
				}
				else if (ReturnValuesOnlyForLastDepth)
				{
					if (pParentNode.Depth == pUltimaDepthCheck)
					{
						plDatas.Add (GetNodeData (pParentNode));
					}
				}
				else
				{
					plDatas.Add (GetNodeData (pParentNode));
				}
			}
		
			foreach (TreeNode childNode in pParentNode.ChildNodes)
			{
				GetDatasForCheckedNodes (childNode, ref plDatas, pDepthCheck, pUltimaDepthCheck);
			}
		}
		
		
		public bool IsThereCheckedNodes ()
		{
			foreach (TreeNode rootNode in base.Nodes)
			{
				if (IsThereCheckedNodes (rootNode))
				{
					return true;
				}
			}
			
			return false;
		}
		
		
		private bool IsThereCheckedNodes (TreeNode pParentNode)
		{
			if (pParentNode.Checked)
			{
				return true;
			}
			
			foreach (TreeNode childNode in pParentNode.ChildNodes)
			{
				if (IsThereCheckedNodes (childNode))
				{
					return true;
				}
			}
			
			return false;
		}
		
		
		public bool HasCheckedNodes ()
		{
			foreach (TreeNode rootNode in base.Nodes)
			{
				if (HasCheckedNodes (rootNode))
				{
					return true;
				}
			}
			
			return false;
		}
		
		
		private bool HasCheckedNodes (TreeNode pParentNode)
		{
			if (pParentNode.Selected)
			{
				return true;
			}
			
			foreach (TreeNode childNode in pParentNode.ChildNodes)
			{
				if (HasCheckedNodes (childNode))
				{
					return true;
				}
			}
			
			return false;
		}
		
		
		public int GetLastDepthOfCheckedNodes ()
		{
			int pDepthCheck;
			
			
			pDepthCheck = DIFX;
		
			foreach (TreeNode nodoPrincipal in base.Nodes)
			{
				GetDepthChecks (nodoPrincipal, ref pDepthCheck);
			}
			
			return pDepthCheck;
		}
		
		
		private void GetDepthChecks (TreeNode pParentNode, ref int pDepthCheck)
		{
			if (pParentNode.Checked)
			{
				if (pParentNode.Depth > pDepthCheck)
				{
					pDepthCheck = pParentNode.Depth;
				}
			}
			
			foreach (TreeNode childNode in pParentNode.ChildNodes)
			{
				GetDepthChecks (childNode, ref pDepthCheck);
			}
		}
		
		#endregion
		
		
		#region Manejo de Eventos del Arbol

        private void ShowChildren (TreeNode pNodo)
        {
            object[] datas;
            Dictionary <string,string> datosNodoActual;


            datosNodoActual = GetNodeData(pNodo);

            // Esta definida la funcion de carga y no tiene nodos relacioandos 
            // (ya fue procesado sino tendria al menos uno el de carga)
            if (SelectNodeGetChildren != null)
            {
				datas = SelectNodeGetChildren(datosNodoActual, true, pNodo.Depth);

				pNodo.ChildNodes.Clear();

				if (datas == null || datas.Length == 0)
				{
					if (ThereIsNoChildrenNodes != null)
					{
						ThereIsNoChildrenNodes(datosNodoActual);
					}
				}
				else if (pNodo.ChildNodes.Count == 0)
				{
					AddNodes(pNodo, datas);
				}
            }
			else
			{
				pNodo.ChildNodes.Clear ();
			}
        }


        //public void TreeNode_PopulateNode(Object sender, TreeNodeEventArgs e)
        //{
           
        //}


		private void GenericTreeView_SelectedNodeChanged (object pSender, EventArgs pParamEvento)
		{
		    if (SelectNodeGetChildren != null)
		    {
				SelectNodeGetChildren (GetSelectedNodeData (), false, base.SelectedNode.Depth);
		    }
		}


        private void GenericTreeView_TreeNodeExpanded(object sender, TreeNodeEventArgs e)
        {
            ShowChildren(e.Node);
        }
		
		
		private void TreeView_CheckedNode(object sender, TreeNodeEventArgs e)
		{
			if (e.Node.Checked)
			{
				// Debe verificar que los Parents de sus Parents deben estar marcados
				CheckParents (e.Node, e.Node.Checked);
				
				if (MarkNode != null)
				{
					MarkNode (GetNodeData (e.Node));
				}
			}
			else
			{
				// Debe verificar que los hijos de sus hijos esten desmarcados
				CheckChildren (e.Node, e.Node.Checked);
			}
		}
		
		#endregion
		
		
		#region Funciones de Presentacion
		
		public void UnCheckNodes ()
		{
			CheckNodes (false);
		}
		
		
		public void CheckNodes (bool pCheck)
		{
			foreach (TreeNode mainNode in base.Nodes)
			{
				CheckNodes (mainNode, pCheck);
			}
		}
		
		
		private void CheckNodes (TreeNode pParentNode, bool pCheck)
		{
			pParentNode.Checked = pCheck;
		
			foreach (TreeNode pchildNode in pParentNode.ChildNodes)
			{
				CheckNodes (pchildNode, pCheck);
			}
		}
		
		#endregion


		#region Funciones de Archivos

		// Code: FullName
		// Name: Name
		// Extra_I: Tiene el URL del directorio o del archivo
		// Extra_II: Indica si es directorio en true.
		// Extra_III: URL de la imagen a presentar como icono
		
		public object [] treeView_SelectNodeGetChildren(Dictionary<string,string> pValueList, bool pFromExpand, int pDepth)
		{
			// Es un directorio se expande
 			if (!bool.Parse (pValueList ["Extra_II"]))
			{
				return null;
			}
			
			return GenerateLevel (pValueList ["Code"]).ToArray ();
		}



		protected List<BasicReference> GenerateLevel (string pParentDirFullname)
		{
			BasicReference currentNode;

			List<BasicReference> items;


			items = new List<BasicReference> ();

			
			foreach (DirectoryInfo dir in new DirectoryInfo (pParentDirFullname).GetDirectories ())
			{
				currentNode = GenerateNode (dir);
				
				if (currentNode != null)
				{
					items.Add (currentNode);
				}
			}


			foreach (FileInfo file in new DirectoryInfo (pParentDirFullname).GetFiles (ExtensionFilter))
			{
				currentNode = GenerateNode (file);
				
				if (currentNode != null)
				{
					items.Add (currentNode);
				}
			}

			return items;
		}


		private BasicReference GenerateNode (DirectoryInfo pDir)
		{
			Page dummyPage;


			if (pDir.Name.StartsWith (".")) { return null; }

			dummyPage = new Page ();

			return new BasicReference ()
			{
				Code = pDir.FullName,
				Name = pDir.Name,
				//Extra_I = (IncludeHyperLinks ? PageHelper.GetVirtualPath (pDir.FullName) : string.Empty),
				Extra_II = bool.TrueString,
				Extra_III = dummyPage.ClientScript.GetWebResourceUrl (typeof (ESF.Web.JS), "ESF.Web.ServerControls.Images.Files.Folder_24x24.png")
			};
		}


		private BasicReference GenerateNode (FileInfo pFile)
		{
			string [] excludedExtensions;
			string fileExtension;


			excludedExtensions = ExcludedExtensions;

			if (excludedExtensions != null)
			{
				fileExtension = pFile.Extension;

				if (!string.IsNullOrEmpty (fileExtension))
				{
					foreach (string ext in excludedExtensions)
					{
						if (string.Compare (ext, fileExtension, true) == 0)
						{
							return null;
						}
					}
				}
			} 

			return new BasicReference ()
			{
				Code = pFile.FullName,
				Name = pFile.Name,
				Extra_I = (IncludeHyperLinks ? PageHelper.GetVirtualPath (pFile.FullName, PublishFolderRelativePath, false) : string.Empty),
				Extra_II = bool.FalseString,
				Extra_III = GetFileImageIconURLByExtension (Path.GetExtension (pFile.FullName))
			};
		}


		protected virtual string GetFileImageIconURLByExtension (string pFileExtension)
		{
			Page dummyPage;


			dummyPage = new Page ();

			switch (pFileExtension.ToUpper ())
			{
				case ".PDF": 
					return dummyPage.ClientScript.GetWebResourceUrl (typeof (ESF.Web.JS), "ESF.Web.ServerControls.Images.Files.PDF_24x24.png");
				
				case ".DOC":
				case ".DOCX": 
					return dummyPage.ClientScript.GetWebResourceUrl (typeof (ESF.Web.JS), "ESF.Web.ServerControls.Images.Files.DOC_24x24.png");

				case ".BMP": 
					return dummyPage.ClientScript.GetWebResourceUrl (typeof (ESF.Web.JS), "ESF.Web.ServerControls.Images.Files.BMP_24x24.png");

				case ".GIF": 
					return dummyPage.ClientScript.GetWebResourceUrl (typeof (ESF.Web.JS), "ESF.Web.ServerControls.Images.Files.GIF_24x24.png");

				case ".JPG": 
				case ".JPEG": 
					return dummyPage.ClientScript.GetWebResourceUrl (typeof (ESF.Web.JS), "ESF.Web.ServerControls.Images.Files.JPG_24x24.png");

				case ".PNG": 
					return dummyPage.ClientScript.GetWebResourceUrl (typeof (ESF.Web.JS), "ESF.Web.ServerControls.Images.Files.PNG_24x24.png");

				default:
					return dummyPage.ClientScript.GetWebResourceUrl (typeof (ESF.Web.JS), "ESF.Web.ServerControls.Images.Files.File_24x24.png");
			}
		}


		public void Browse ()
		{
			TreeNode node;


			FileHelper.EnsureFolder (PublishFolder);

			foreach (DirectoryInfo dir in new DirectoryInfo (PublishFolder).GetDirectories ())
			{
				node = GenerateNode (GenerateNode (dir), 0);
				
				if (node != null)
				{
					Nodes.Add (node);
				}
			}


			foreach (FileInfo file in new DirectoryInfo (PublishFolder).GetFiles (ExtensionFilter))
			{
				node = GenerateNode (GenerateNode (file), 0);

				if (node != null)
				{
					Nodes.Add (node);
				}
			}
		}

		#endregion
	}
}


